package com.redepronik.negosysres.invfac.controller;

import static com.redepronik.negosys.utils.Utils.divide;
import static com.redepronik.negosys.utils.Utils.fechaFormatoDate;
import static com.redepronik.negosys.utils.Utils.newBigDecimal;
import static com.redepronik.negosys.utils.Utils.redondear;
import static com.redepronik.negosys.utils.Utils.timestamp;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;

import org.primefaces.event.CellEditEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;

import com.redepronik.negosys.invfac.entity.Bodega;
import com.redepronik.negosys.invfac.entity.Detalleegreso;
import com.redepronik.negosys.invfac.entity.Egreso;
import com.redepronik.negosys.invfac.entity.Entrada;
import com.redepronik.negosys.invfac.entity.Local;
import com.redepronik.negosys.invfac.entity.Pagoentrada;
import com.redepronik.negosys.invfac.entity.Producto;
import com.redepronik.negosys.invfac.entity.Tipopago;
import com.redepronik.negosys.invfac.entityAux.CantidadFactura;
import com.redepronik.negosys.invfac.entityAux.EntradaReporte;
import com.redepronik.negosys.invfac.entityAux.FacturaReporte;
import com.redepronik.negosys.invfac.service.EgresoService;
import com.redepronik.negosys.invfac.service.KardexService;
import com.redepronik.negosys.invfac.service.LocalService;
import com.redepronik.negosys.invfac.service.ProductoService;
import com.redepronik.negosys.invfac.service.TipoDocumentoService;
import com.redepronik.negosys.invfac.service.TipoPagoService;
import com.redepronik.negosys.rrhh.entity.Persona;
import com.redepronik.negosys.rrhh.service.ClienteService;
import com.redepronik.negosysres.invfac.report.EgresoReport;

@Controller
@Scope("session")
public class FacturaInternaBean implements Serializable {

	private static final long serialVersionUID = 1L;

	@Autowired
	private EgresoService egresoService;

	@Autowired
	private ProductoService productoService;

	@Autowired
	private KardexService kardexService;

	@Autowired
	private ClienteService clienteService;

	@Autowired
	private LocalService localService;

	@Autowired
	private TipoDocumentoService tipoDocumentoService;

	@Autowired
	private TipoPagoService tipoPagoService;

	@Autowired
	private EgresoReport egresoReport;

	private List<Tipopago> listTiposPago;
	private List<EntradaReporte> listaEntradaReporte;

	private Egreso egreso;
	private Persona cliente;
	private Entrada entrada;
	private Pagoentrada pagosEntrada;
	private Tipopago tiposPago;
	private Date fechaInicio;

	private Producto producto;

	private List<FacturaReporte> facturaReportes;
	private FacturaReporte facturaReporte;
	private CantidadFactura cantidadFacturaCalculos;
	private CantidadFactura cantidadFacturaPresentar;
	private BigDecimal restante;
	private BigDecimal restanteAux;
	private BigDecimal cambio;
	private BigDecimal totalMonto;

	private Integer cantidad;
	private BigDecimal nuevoPrecio;
	private BigDecimal importe;

	private Bodega bodega;
	private Integer fila;

	private boolean bn = false;

	public FacturaInternaBean() {
		listTiposPago = new ArrayList<Tipopago>();
		listaEntradaReporte = new ArrayList<EntradaReporte>();

		xxx();
		cliente = new Persona();
		entrada = new Entrada();
		pagosEntrada = new Pagoentrada();
		tiposPago = new Tipopago();
		fechaInicio = new Date();
		producto = new Producto();
		facturaReportes = new ArrayList<FacturaReporte>();
		facturaReporte = new FacturaReporte();
		cantidadFacturaCalculos = new CantidadFactura();
		cantidadFacturaPresentar = new CantidadFactura();
		restante = newBigDecimal();
		cambio = newBigDecimal();
		totalMonto = new BigDecimal("0");
	}

	public void calcularEntrada() {
		EntradaReporte entradaReporte = new EntradaReporte();
		if (entrada.getFechapago() != null) {
			pagosEntrada.setCuota(entrada.getCuota());
			pagosEntrada.setTipopago(tiposPago);
			pagosEntrada.setFechapago(timestamp(entrada.getFechapago()));
			pagosEntrada.setPagado(true);
			entrada.setPagado(true);
			entrada.setSaldo(new BigDecimal("0"));
			entrada.setFechamora(fechaFormatoDate("01-01-1900"));
			entradaReporte.setFechaPago(entrada.getFechapago());
			entradaReporte.setPagado(true);
			entrada.addPagoentrada(pagosEntrada);
			egreso.addEntrada(entrada);
		} else if (tiposPago.getTipopagoid() == 3) {
			entrada.setPagado(false);
			entrada.setSaldo(entrada.getCuota());
			entrada.setFechamora(fechaFormatoDate("01-01-1900"));
			pagosEntrada.setCuota(entrada.getCuota());
			pagosEntrada.setTipopago(tiposPago);
			pagosEntrada.setFechapago(timestamp("01-01-1900"));
			pagosEntrada.setPagado(false);
			entrada.addPagoentrada(pagosEntrada);
			egreso.addEntrada(entrada);
			entradaReporte.setPagado(false);
		} else {
			entrada.setPagado(false);
			entrada.setSaldo(entrada.getCuota());
			Calendar c = new GregorianCalendar();
			c.setTime(fechaInicio);
			c.add(Calendar.DATE, 15);
			entrada.setFechamora(c.getTime());
			entradaReporte.setPagado(false);
			egreso.addEntrada(entrada);
		}
		entradaReporte.setFecha(entrada.getFechalimite());
		entradaReporte.setCuota(entrada.getCuota());

		if (tiposPago.getTipopagoid() != 0)
			entradaReporte.setTipoPago(tipoPagoService.obtenerPorTipoPagoId(
					tiposPago.getTipopagoid()).getNombre());

		BigDecimal tm = new BigDecimal("0");
		List<Entrada> list = egreso.getEntradas();
		for (Entrada e : list)
			tm = tm.add(e.getCuota());

		totalMonto = tm;
		restante = restanteAux = cantidadFacturaCalculos.getTotal().subtract(
				totalMonto);
		if (totalMonto.compareTo(cantidadFacturaCalculos.getTotal()) > 0)
			cambio = totalMonto.subtract(cantidadFacturaCalculos.getTotal());

		listaEntradaReporte.add(entradaReporte);

	}

	public void cambiarCantidad() {
		if (fila == null)
			presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
					"MENSAJE DEL SISTEMA",
					"PRESIONE ENTER O TAB PARA CAMBIAR LA CANTIDAD"));
		else {
			FacturaReporte f = facturaReportes.get(fila);

			if (cantidad <= 0)
				presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
						"ERROR", "INGRESE UNA CANTIDAD MAYOR QUE CERO"));
			else if (cantidad != f.getCantidad())
				facturaReportes.set(fila, egresoService.recalcular(fila, f,
						egreso.getDetalleegresos(), cantidadFacturaCalculos,
						cantidad, null, bn));

			cantidad = null;
			fila = null;
		}
	}

	public void cambiarDescuento() {
		if (cantidadFacturaPresentar.getDescuentoEgreso().compareTo(
				cantidadFacturaPresentar.getTotal()) > 0
				|| cantidadFacturaPresentar.getDescuentoEgreso().compareTo(
						newBigDecimal()) < 0)
			presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
					"ERROR", "INGRESE UN DESCUENTO VALIDO"));
		else {
			cantidadFacturaCalculos.setDescuentoEgreso(cantidadFacturaPresentar
					.getDescuentoEgreso());
			egreso.setDescuento(cantidadFacturaCalculos.getDescuentoEgreso());
			if (bn) {
				cantidadFacturaCalculos
						.setSubTotal(redondear(cantidadFacturaCalculos
								.getSubTotalIva()
								.add(cantidadFacturaCalculos
										.getSubTotalNoIva()
										.subtract(
												cantidadFacturaCalculos
														.getDescuentoEgreso())
										.subtract(
												cantidadFacturaCalculos
														.getDescuentoProducto()))));

				cantidadFacturaCalculos
						.setTotal(redondear(cantidadFacturaCalculos
								.getSubTotal().add(
										cantidadFacturaCalculos.getIva())));

				cantidadFacturaCalculos
						.setBaseRetencion(redondear(cantidadFacturaCalculos
								.getSubTotal()));
			} else
				cantidadFacturaCalculos
						.setTotal(redondear(cantidadFacturaCalculos
								.getSubTotal()
								.subtract(
										cantidadFacturaCalculos
												.getDescuentoEgreso())
								.subtract(
										cantidadFacturaCalculos
												.getDescuentoProducto())));
		}
	}

	public void cambiarImporte() {
		if (fila == null)
			presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
					"MENSAJE DEL SISTEMA",
					"PRESIONE ENTER O TAB PARA CAMBIAR EL PRECIO"));
		else {
			FacturaReporte f = facturaReportes.get(fila);

			nuevoPrecio = divide(importe, new BigDecimal(f.getCantidad()));

			if (nuevoPrecio.compareTo(newBigDecimal()) <= 0)
				presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
						"ERROR", "EL PRECIO NO DEBE SER MENOR A CERO"));
			else if (nuevoPrecio != f.getPrecioUnitVenta())
				facturaReportes.set(fila, egresoService.recalcular(fila, f,
						egreso.getDetalleegresos(), cantidadFacturaCalculos,
						null, nuevoPrecio, bn));

			nuevoPrecio = null;
			fila = null;
		}
	}

	public void cambiarPrecio() {
		if (fila == null)
			presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
					"MENSAJE DEL SISTEMA",
					"PRESIONE ENTER O TAB PARA CAMBIAR EL PRECIO"));
		else {
			FacturaReporte f = facturaReportes.get(fila);

			if (nuevoPrecio.compareTo(newBigDecimal()) <= 0)
				presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_ERROR,
						"ERROR", "EL PRECIO NO DEBE SER MENOR A CERO"));
			else if (nuevoPrecio != f.getPrecioUnitVenta())
				facturaReportes.set(fila, egresoService.recalcular(fila, f,
						egreso.getDetalleegresos(), cantidadFacturaCalculos,
						null, nuevoPrecio, bn));

			nuevoPrecio = null;
			fila = null;
		}
	}

	public void cancelar() {
		facturaReporte = new FacturaReporte();
	}

	public void cancelarEntrada() {
		entrada = new Entrada();
		pagosEntrada = new Pagoentrada();
		tiposPago = new Tipopago();
	}

	public void cancelarPago() {
		listaEntradaReporte = new ArrayList<EntradaReporte>();
		egreso.setEntradas(new ArrayList<Entrada>());
		cambio = newBigDecimal();
		restante = cantidadFacturaCalculos.getTotal();
		cancelarEntrada();
	}

	public void cancelarTodo() {
		xxx();
		cliente = new Persona();
		entrada = new Entrada();
		pagosEntrada = new Pagoentrada();
		fechaInicio = new Date();
		listaEntradaReporte = new ArrayList<EntradaReporte>();
		facturaReportes = new ArrayList<FacturaReporte>();
		cantidadFacturaCalculos = new CantidadFactura();
		restante = newBigDecimal();
		cambio = newBigDecimal();
	}

	public void convertirFacturaInterna(Egreso egreso) {
		cancelarTodo();
		this.egreso = egresoService.obtenerPorEgresoId(egreso.getEgresoid());
		cliente = egreso.getCliente().getPersona();
		if (egreso.getDescuento() != null)
			cantidadFacturaCalculos.setDescuentoEgreso(egreso.getDescuento());

		this.bn = egresoService.facturaNotaEntrega(egreso.getCodigodocumento());

		int tipoDocumentoId = 0;
		if (egresoService.facturaNotaEntrega(egreso.getCodigodocumento()))
			tipoDocumentoId = 1;
		else
			tipoDocumentoId = 8;

		List<Detalleegreso> list = egreso.getDetalleegresos();
		for (Detalleegreso detalleEgreso : list) {
			FacturaReporte fr = egresoService.asignar(detalleEgreso, null,
					tipoDocumentoId);

			if (bn)
				cantidadFacturaCalculos = egresoService
						.calcularCantidadFactura(cantidadFacturaCalculos, fr,
								"add");
			else
				cantidadFacturaCalculos = egresoService
						.calcularCantidadNotaEntrega(cantidadFacturaCalculos,
								fr, "add");

			facturaReportes.add(fr);
		}
	}

	public void eliminarDetalle(ActionEvent actionEvent) {
		int posicion = egresoService.posicion(facturaReporte,
				egreso.getDetalleegresos(), bn);
		if (posicion >= 0) {
			Detalleegreso de = egreso.getDetalleegresos().get(posicion);
			presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_INFO,
					"ELIMINÓ DETALLE", "Elimino: " + de.getProducto().getEan()));
			egreso.removeDetalleegreso(de);
			if (bn)
				cantidadFacturaCalculos = egresoService
						.calcularCantidadFactura(cantidadFacturaCalculos,
								facturaReporte, "subtract");
			else
				cantidadFacturaCalculos = egresoService
						.calcularCantidadNotaEntrega(cantidadFacturaCalculos,
								facturaReporte, "subtract");

			restante = restanteAux = cantidadFacturaCalculos.getTotal();
			facturaReportes.remove(facturaReporte);
			cancelar();
		}
	}

	public BigDecimal getCambio() {
		return cambio;
	}

	public Integer getCantidad() {
		return cantidad;
	}

	public CantidadFactura getCantidadFacturaCalculos() {
		return cantidadFacturaCalculos;
	}

	public CantidadFactura getCantidadFacturaPresentar() {
		return egresoService.redondearCantidadFactura(cantidadFacturaPresentar,
				cantidadFacturaCalculos);
	}

	public Persona getCliente() {
		return cliente;
	}

	public Egreso getEgreso() {
		if (egreso.getEgresoid() == null) {
			egreso.setTipodocumento(tipoDocumentoService.obtenerPorId(9));
			egreso.setCodigodocumento(egreso.getTipodocumento()
					.getAbreviatura() + "-" + egreso.getCodigodocumento());
		}

		return egreso;
	}

	public Entrada getEntrada() {
		if (entrada.getPagoentradas() == null)
			entrada.setPagoentradas(new ArrayList<Pagoentrada>());
		return entrada;
	}

	public FacturaReporte getFacturaReporte() {
		return facturaReporte;
	}

	public List<FacturaReporte> getFacturaReportes() {
		return facturaReportes;
	}

	public Date getFechaInicio() {
		return fechaInicio;
	}

	public BigDecimal getImporte() {
		return importe;
	}

	public List<EntradaReporte> getListaEntradaReporte() {
		return listaEntradaReporte;
	}

	public List<Tipopago> getListTiposPago() {
		listTiposPago = tipoPagoService.obtener();
		return listTiposPago;
	}

	public BigDecimal getNuevoPrecio() {
		return nuevoPrecio;
	}

	public Pagoentrada getPagosEntrada() {
		return pagosEntrada;
	}

	public Producto getProducto() {
		return producto;
	}

	public BigDecimal getRestante() {
		return restante;
	}

	public BigDecimal getRestanteAux() {
		return restanteAux;
	}

	public Tipopago getTiposPago() {
		return tiposPago;
	}

	public BigDecimal getTotalMonto() {
		return totalMonto;
	}

	public void insertarOrActualizar(ActionEvent actionEvent) {
		boolean pagado = true;

		List<Entrada> list = egreso.getEntradas();

		if (list.isEmpty() && egreso.getCredito() == null)
			pagado = false;

		for (Entrada e : list)
			if (e.getPagado() == false
					|| e.getCuota().compareTo(
							cantidadFacturaCalculos.getTotal()) < 0)
				pagado = false;

		if (egreso.getCredito() != null)
			if (egreso.getCredito().getPagado() == false)
				pagado = false;

		egreso.setPagado(pagado);

		egresoService.actualizar(egreso, bodega);
		presentaMensaje(new FacesMessage(FacesMessage.SEVERITY_INFO,
				"ACTUALIZO", "Egreso: " + egreso.getCodigodocumento()));

		cancelarTodo();

		try {
			FacesContext.getCurrentInstance().getExternalContext()
					.redirect("listadoFacturaInterna.jsf");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public boolean isBn() {
		return bn;
	}

	public void obtenerBodega() {
		Local local = localService.obtenerPorLocalId(egreso.getLocal()
				.getLocalid());
		if (local.getBodegalocals() != null
				&& !local.getBodegalocals().isEmpty())
			bodega = local.getBodegalocals().get(0).getBodega();
	}

	public void obtenerFila(CellEditEvent event) {
		fila = event.getRowIndex();
	}

	private void presentaMensaje(FacesMessage message) {
		FacesContext.getCurrentInstance().addMessage(null, message);
	}

	public void setBn(boolean bn) {
		this.bn = bn;
	}

	public void setCambio(BigDecimal cambio) {
		this.cambio = cambio;
	}

	public void setCantidad(Integer cantidad) {
		this.cantidad = cantidad;
	}

	public void setCantidadFacturaCalculos(
			CantidadFactura cantidadFacturaCalculos) {
		this.cantidadFacturaCalculos = cantidadFacturaCalculos;
	}

	public void setCantidadFacturaPresentar(
			CantidadFactura cantidadFacturaPresentar) {
		this.cantidadFacturaPresentar = cantidadFacturaPresentar;
	}

	public void setCliente(Persona cliente) {
		this.cliente = cliente;
	}

	public void setEgreso(Egreso egreso) {
		this.egreso = egreso;
	}

	public void setEntrada(Entrada entrada) {
		this.entrada = entrada;
	}

	public void setFacturaReporte(FacturaReporte facturaReporte) {
		this.facturaReporte = facturaReporte;
	}

	public void setFacturaReportes(List<FacturaReporte> facturaReportes) {
		this.facturaReportes = facturaReportes;
	}

	public void setFechaInicio(Date fechaInicio) {
		this.fechaInicio = fechaInicio;
	}

	public void setImporte(BigDecimal importe) {
		this.importe = importe;
	}

	public void setListaEntradaReporte(List<EntradaReporte> listaEntradaReporte) {
		this.listaEntradaReporte = listaEntradaReporte;
	}

	public void setListTiposPago(List<Tipopago> listTiposPago) {
		this.listTiposPago = listTiposPago;
	}

	public void setNuevoPrecio(BigDecimal nuevoPrecio) {
		this.nuevoPrecio = nuevoPrecio;
	}

	public void setPagosEntrada(Pagoentrada pagosEntrada) {
		this.pagosEntrada = pagosEntrada;
	}

	public void setProducto(Producto producto) {
		this.producto = producto;
	}

	public void setRestante(BigDecimal restante) {
		this.restante = restante;
	}

	public void setRestanteAux(BigDecimal restanteAux) {
		this.restanteAux = restanteAux;
	}

	public void setTiposPago(Tipopago tiposPago) {
		this.tiposPago = tiposPago;
	}

	public void setTotalMonto(BigDecimal totalMonto) {
		this.totalMonto = totalMonto;
	}

	private void xxx() {
		egreso = new Egreso();
		egreso.setLocal(new Local());
		// egreso.setVendedor(new Vendedor());
		egreso.setEntradas(new ArrayList<Entrada>());
		egreso.setDetalleegresos(new ArrayList<Detalleegreso>());
	}

}